package jp.ac.kobe_u.cs.cream;

import jp.ac.kobe_u.cs.cream.*;
import java.util.*;

public class SASearch extends LocalSearch {
    private double gamma = 0.999;
    private double temperature = 100.0;

    public SASearch(Network network) {
	this(network, DEFAULT, null);
    }

    public SASearch(Network network, int option) {
	this(network, option, null);
    }

    public SASearch(Network network, String name) {
	this(network, DEFAULT, name);
    }

    public SASearch(Network network, int option, String name) {
	super(network, option, name);
	setExchangeRate(0.05);
    }

    public synchronized void setTemperature(double temp) {
	temperature = temp;
    }

    public synchronized double getTemperature() {
	return temperature;
    }

    protected void startSearch() {
	super.startSearch();
	temperature = (double)solution.getObjectiveIntValue() / 10.0;
    }

    protected void nextSearch() {
	if (totalTimeout > 0) {
	    long elapsedTime = Math.max(1, System.currentTimeMillis() - startTime);
	    double iterationRate = (double)iteration / (double)elapsedTime;
	    int expectedIteration = (int)(iterationRate * (totalTimeout - elapsedTime));
	    if (expectedIteration > 0) {
		gamma = Math.exp(Math.log(1.0/temperature)/(double)expectedIteration);
		gamma = Math.min(0.9999, gamma);
	    }
	}
	temperature *= gamma;
	solution = candidate();
	int value = solution.getObjectiveIntValue();
	Code code = solution.getCode();
	List operations = code.operations();
	while (operations.size() > 0) {
	    int i = (int)(operations.size() * Math.random());
	    Operation op = (Operation)operations.remove(i);
	    code.setTo(network);
	    op.applyTo(network);
	    Solution sol = solver.findBest(iterationTimeout);
	    if (sol == null)
		continue;
	    double delta = sol.getObjectiveIntValue() - value;
	    if (isOption(MAXIMIZE)) {
		delta = -delta;
	    }
	    if (delta < 0) {
		solution = sol;
		return;
	    }
	    double p = Math.exp(-delta/temperature);
	    if (p < Math.random())
		continue;
	    solution = sol;
	    return;
	}
	solution = null;
    }
}
